package com.ethink.order.manager;
import java.time.LocalDateTime;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ethink.framework.common.constant.CommonRespCode;
import com.ethink.framework.common.exception.BusinessException;
import com.ethink.framework.common.web.context.SPRequestContextHolder;
import com.ethink.order.api.constant.OrderConstant;
import com.ethink.order.api.constant.OrderRespCode;
import com.ethink.order.api.enums.SaleOrderOrderStatusEnum;
import com.ethink.order.api.enums.SaleOrderOrderTypeEnum;
import com.ethink.order.api.enums.TobSaleOrderOrderStatusEnum;
import com.ethink.order.api.info.SaleDetailOrderInfo;
import com.ethink.order.api.info.TobSaleDetailOrderInfo;
import com.ethink.order.api.info.TobSaleSettlementDetailOrderInfo;
import com.ethink.order.api.model.TobSaleOrderAndReturnModel;
import com.ethink.order.api.request.SaleDetailOrderAddRequest;
import com.ethink.order.api.request.SaleOrderAddRequest;
import com.ethink.order.api.request.TobOrderSettleUpdateRequest;
import com.ethink.order.api.request.TobSaleOrderUpdateRequest;
import com.ethink.order.api.response.SaleOrderAddResponse;
import com.ethink.order.api.response.TobSaleOrderDetailResponse;
import com.ethink.order.api.response.TobSaleSettlementQueryDetailResponse;
import com.ethink.order.common.entity.SettlementSale;
import com.ethink.order.common.entity.TobSaleDetailOrder;
import com.ethink.order.common.entity.TobSaleOrder;
import com.ethink.order.common.mapper.SettlementSaleMapper;
import com.ethink.order.common.mapper.TobSaleDetailOrderMapper;
import com.ethink.order.common.mapper.TobSaleOrderMapper;
import com.ethink.order.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author default
 * @version 1.0.0
 * @ClassName TobSaleManager.java
 * @Description
 * @createTime 2022年11月16日 18:18:00
 */
@Component
@Slf4j
public class TobSaleManager {

    @Autowired
    private TobSaleDetailOrderService tobSaleDetailOrderService;

    @Autowired
    private TobSaleOrderMapper tobSaleOrderMapper;

    @Autowired
    private TobSaleDetailOrderMapper tobSaleDetailOrderMapper;

    @Autowired
    private TobSaleSettlementDetailOrderService tobSaleSettlementDetailOrderService;

    @Autowired
    private TobSaleOrderService tobSaleOrderService;

    @Autowired
    private SaleOrderService saleOrderService;

    public final static String CONNECTOR_STR = "-";

    @Autowired
    private TobSaleSettlementOrderService tobSaleSettlementOrderService;

    @Autowired
    private SettlementSaleMapper settlementSaleMapper;

    @Transactional(rollbackFor = Exception.class)
    public Integer updateTobSaleOrder(TobSaleOrderUpdateRequest request) {
        TobSaleOrder order = tobSaleOrderMapper.selectById(request.getId());
        if (!TobSaleOrderOrderStatusEnum.S1.eq(order.getOrderStatus())) {
            throw new BusinessException(OrderRespCode.SALE_ORDER_DETAIL_STATUS_IS_NOT_MET);
        }
        TobSaleOrder tobSaleOrder = BeanUtil.copyProperties(request, TobSaleOrder.class, "item");
        tobSaleDetailOrderMapper.delete(new LambdaQueryWrapper<TobSaleDetailOrder>()
                .eq(TobSaleDetailOrder::getOrderNo, order.getOrderNo()));
        tobSaleDetailOrderService.batchInsert(request.getItem(), order.getOrderNo());
        return tobSaleOrderMapper.updateById(tobSaleOrder);
    }

    public TobSaleOrderDetailResponse queryDetailTobSaleOrder(Long id, Integer table) {
        TobSaleOrderDetailResponse response = new TobSaleOrderDetailResponse();
        TobSaleOrder tobSaleOrder = tobSaleOrderMapper.selectById(id);
        if (ObjectUtil.isEmpty(tobSaleOrder)) {
            return response;
        }
        if (table == 1) {
            List<TobSaleDetailOrderInfo> saleItem = tobSaleDetailOrderService.queryDetailOrderByOrderNo(tobSaleOrder.getOrderNo());
            response.setSaleItem(saleItem);
        } else if (table == 2) {
            List<SaleDetailOrderInfo> settleItem = saleOrderService.queryDetailByTobOrderNo(tobSaleOrder.getOrderNo());
            response.setSettleItem(settleItem);
        }
        return response;
    }

    public void settleOrder(Long id) {
        TobSaleSettlementQueryDetailResponse response = tobSaleSettlementOrderService.queryDetail(id);
        if (OrderConstant.Z102.equals(response.getMain().getSaleSubChannel())) {
            weiPinSettleOrder(response);
        } else {
            otherSettleOrder(response);
        }
        tobSaleSettlementOrderService.matchConfirm(id);
    }

    public void weiPinSettleOrder(TobSaleSettlementQueryDetailResponse response) {
        String saleSubChannel = response.getMain().getSaleSubChannel();
        //唯品
        List<String> mateSkuList = new ArrayList<>();
        List<String> poAndSkuList = new ArrayList<>();
        Map<String, TobSaleSettlementDetailOrderInfo> mapInfo = new HashMap<>();
        Map<String, Integer> mapQty = new HashMap<>();
        for (TobSaleSettlementDetailOrderInfo info : response.getItem()) {
            mateSkuList.add(info.getMateSku());
            poAndSkuList.add(info.getPoOrderNo() + CONNECTOR_STR + info.getMateSku());
            mapInfo.put(info.getPoOrderNo() + CONNECTOR_STR + info.getMateSku(), info);
            mapQty.put(info.getPoOrderNo() + CONNECTOR_STR + info.getMateSku(), info.getSettleQty());
        }
        List<TobSaleOrderAndReturnModel> infoList = tobSaleOrderService.queryToBeSettleDetailByPo(mateSkuList, saleSubChannel, poAndSkuList);
        ;
        if (infoList.size() == 1) {
            infoList.removeAll(Collections.singleton(null));
        }
        if (CollUtil.isEmpty(infoList)) {
            throw new BusinessException(CommonRespCode.PARAM_ERR, "未匹配到预售商品信息,无法结算");
        }
        checkProductMathch(response,infoList);
        //以po单号加商品编码分组
        Map<String, List<TobSaleOrderAndReturnModel>> poGroup = infoList.stream()
                .collect(Collectors.groupingBy(TobSaleOrderAndReturnModel::getPoOrderNo));
        //销售单批量新增对象
        tobSaleSettleAndCreateSaleOrder(response, saleSubChannel, mapInfo, mapQty, poGroup);
    }

    /**
     * 预售单结算和生成销售订单
     *
     * @param response          财务结算明细
     * @param saleSubChannel    订单来源
     * @param mapInfo
     * @param mapQty
     * @param poAndMateSkuGroup 预售单分组对象
     */
    private void tobSaleSettleAndCreateSaleOrder(TobSaleSettlementQueryDetailResponse response, String saleSubChannel
            , Map<String, TobSaleSettlementDetailOrderInfo> mapInfo, Map<String, Integer> mapQty, Map<String, List<TobSaleOrderAndReturnModel>> poAndMateSkuGroup) {
        String userCode = SPRequestContextHolder.getCurrentSystemUserLoginName();
        String userName = SPRequestContextHolder.getCurrentSystemUserRealName();
        List<SaleOrderAddRequest> saleOrderAddRequestList = new ArrayList<>();
        Set<String> orderNoSet = new HashSet<>();
        for (Map.Entry<String, List<TobSaleOrderAndReturnModel>> listEntry : poAndMateSkuGroup.entrySet()) {
            SaleOrderAddRequest saleOrderAddRequest = new SaleOrderAddRequest();
            saleOrderAddRequest.setOrderType(SaleOrderOrderTypeEnum.T1.getIntValue());
            saleOrderAddRequest.setOrderStatus(SaleOrderOrderStatusEnum.S4.getIntValue());
            saleOrderAddRequest.setSaleChannel(response.getMain().getSaleChannel());
            saleOrderAddRequest.setSaleSubChannel(saleSubChannel);
            saleOrderAddRequest.setExchangeRate(BigDecimal.ONE);
            saleOrderAddRequest.setCreateUserCode(userCode);
            saleOrderAddRequest.setCreateUserName(userName);
            saleOrderAddRequest.setOrderTime(new Date());
            saleOrderAddRequest.setCurrencyCode(listEntry.getValue().get(0).getCurrencyCode());
            saleOrderAddRequest.setCurrencyName(listEntry.getValue().get(0).getCurrencyName());
            saleOrderAddRequest.setSubWarehouseCode(listEntry.getValue().get(0).getOutSubWarehouseCode());
            saleOrderAddRequest.setSubWarehouseName(listEntry.getValue().get(0).getOutSubWarehouseName());
            if (StrUtil.equals(saleSubChannel, OrderConstant.Z102)) {
                saleOrderAddRequest.setPoOrderNo(listEntry.getKey());
            }
            List<TobOrderSettleUpdateRequest> requestList = new ArrayList<>();
            //销售单详情
            List<SaleDetailOrderAddRequest> saleDetailOrderAddRequestList = new ArrayList<>();
            for (TobSaleOrderAndReturnModel model : listEntry.getValue()) {
                Integer settleQty = mapQty.get(getKey(model, saleSubChannel));
                //结算数量 = 预售数量 - 退货数量 - 已结算数量
                int returnQty = model.getReturnQty() == null ? 0 : model.getReturnQty();
                int toBeSettleQty = model.getQty() - model.getSettleQty() - returnQty;
                if (ObjectUtil.isNotEmpty(settleQty)) {
                    orderNoSet.add(model.getOrderNo());
                    TobSaleSettlementDetailOrderInfo tobSaleSettlementDetailOrderInfo = mapInfo.get(getKey(model, saleSubChannel));
                    SaleDetailOrderAddRequest saleDetailOrderAddRequest = new SaleDetailOrderAddRequest();
                    TobOrderSettleUpdateRequest settleUpdateRequest = new TobOrderSettleUpdateRequest();
                    settleUpdateRequest.setId(model.getId());
                    settleUpdateRequest.setOrderNo(model.getOrderNo());
                    //判断数量大小
                    if (settleQty >= toBeSettleQty) {
                        settleUpdateRequest.setSettleQty(toBeSettleQty);
                        settleUpdateRequest.setIsSettle(true);
                        int surplusQty = settleQty - toBeSettleQty;
                        if (surplusQty == 0) {
                            mapQty.remove(getKey(model, saleSubChannel));
                        } else {
                            mapQty.put(getKey(model, saleSubChannel), surplusQty);
                        }
                    } else {
                        settleUpdateRequest.setSettleQty(settleQty);
                        settleUpdateRequest.setIsSettle(false);
                        //删除改值
                        mapQty.remove(getKey(model, saleSubChannel));
                    }
                    requestList.add(settleUpdateRequest);
                    //销售详情新增对象赋值
                    BeanUtil.copyProperties(model, saleDetailOrderAddRequest, "orderNo", "detailOrderNo");
                    saleDetailOrderAddRequest.setOutQty(settleUpdateRequest.getSettleQty());
                    saleDetailOrderAddRequest.setSalePrice(tobSaleSettlementDetailOrderInfo.getSettlePrice());
                    saleDetailOrderAddRequest.setTobOrderNo(model.getOrderNo());
                    saleDetailOrderAddRequest.setTobDetailOrderNo(model.getDetailOrderNo());
                    saleDetailOrderAddRequestList.add(saleDetailOrderAddRequest);
                }
                //如果map 为空 结束循环
                if (mapQty.size() == 0) {
                    break;
                }
            }
            //更新预售详情状态
            tobSaleDetailOrderService.batchSettleDetail(requestList);
            //销售单新增子项不能为空
            if (CollUtil.isNotEmpty(saleDetailOrderAddRequestList)) {
                saleOrderAddRequest.setItem(saleDetailOrderAddRequestList);
                saleOrderAddRequestList.add(saleOrderAddRequest);
            }
            if (mapQty.size() == 0) {
                break;
            }
        }
        //结算预售单
        tobSaleOrderService.batchSettleOrder(new ArrayList<>(orderNoSet));
        //生成采购单
        Long settleId = response.getMain().getId();
        for (SaleOrderAddRequest saleOrderAddRequest : saleOrderAddRequestList) {
            SaleOrderAddResponse saleOrderAddResponse = saleOrderService.addSaleOrder(saleOrderAddRequest, false);
            SettlementSale settlementSale = new SettlementSale();
            settlementSale.setSettleId(settleId);
            settlementSale.setSaleId(saleOrderAddResponse.getSaleOrderInfo().getId());
            settlementSaleMapper.insert(settlementSale);
        }

    }

    public void otherSettleOrder(TobSaleSettlementQueryDetailResponse response) {
        String saleSubChannel = response.getMain().getSaleSubChannel();
        List<String> mateSkuList = CollUtil.getFieldValues(response.getItem(), "mateSku", String.class);
        //查询预售订单与预售退单相关信息
        List<TobSaleOrderAndReturnModel> infoList = tobSaleOrderService.queryToBeSettleDetail(mateSkuList, saleSubChannel, null);
        if (infoList.size() == 1) {
            infoList.removeAll(Collections.singleton(null));
        }
        if (CollUtil.isEmpty(infoList)) {
            throw new BusinessException(CommonRespCode.PARAM_ERR, "未匹配到预售商品信息,无法结算");
        }
        checkProductMathch(response, infoList);
        //以预售单号分组
        Map<String, List<TobSaleOrderAndReturnModel>> collect = infoList.stream()
                .collect(Collectors.groupingBy(TobSaleOrderAndReturnModel::getOrderNo));
        Map<String, Integer> mapQty = new HashMap<>();
        Map<String, TobSaleSettlementDetailOrderInfo> mapInfo = new HashMap<>();
        for (TobSaleSettlementDetailOrderInfo info : response.getItem()) {
            mapQty.put(info.getMateSku(), info.getSettleQty());
            mapInfo.put(info.getMateSku(), info);
        }
        tobSaleSettleAndCreateSaleOrder(response, saleSubChannel, mapInfo, mapQty, collect);
    }


    public String getKey(TobSaleOrderAndReturnModel model, String saleSubChannel) {
        if (StrUtil.equals(saleSubChannel, OrderConstant.Z102)) {
            return model.getPoOrderNo() + CONNECTOR_STR + model.getMateSku();
        }
        return model.getMateSku();
    }

    private void checkProductMathch(TobSaleSettlementQueryDetailResponse response, List<TobSaleOrderAndReturnModel> infoList) {
        List<String> settleMateSkuList = response.getItem().stream().map(TobSaleSettlementDetailOrderInfo::getMateSku).collect(Collectors.toList());
        List<String> matchMateSkuList = infoList.stream().map(TobSaleOrderAndReturnModel::getMateSku).distinct().collect(Collectors.toList());
        List<String> diffList = settleMateSkuList.stream().filter(item -> !matchMateSkuList.contains(item)).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(diffList)) {
            throw new BusinessException(CommonRespCode.PARAM_ERR, String.format(OrderRespCode.DIFF_MATE_SKU.getMessage(), JSON.toJSONString(diffList)));
        }
        //结算数量不能超出待结算数量
        List<TobSaleSettlementDetailOrderInfo> item = response.getItem();
        Map<String, Integer> TobSettleNumMap = infoList.stream().collect(Collectors.groupingBy(TobSaleOrderAndReturnModel::getMateSku
                , Collectors.summingInt(a -> a.getQty() - a.getSettleQty())));
        List<String> moreNumMateSkuList = response.getItem().stream().filter(a -> a.getSettleQty() > TobSettleNumMap.get(a.getMateSku()))
                .map(TobSaleSettlementDetailOrderInfo::getMateSku).collect(Collectors.toList());

        if (CollUtil.isNotEmpty(moreNumMateSkuList)) {
            throw new BusinessException(CommonRespCode.PARAM_ERR, String.format(OrderRespCode.NUM_MORE_MATE_SKU.getMessage(), JSON.toJSONString(moreNumMateSkuList)));
        }
    }
}
